package thread.sync;

import thread.invariantframework.Invariant;
import thread.invariantframework.InvariantWatcher;
import thread.invariantframework.Timeout;
import thread.invariantframework.state.InvariantFailure;
import thread.invariantframework.state.InvariantOK;
import thread.invariantframework.state.InvariantState;

public class SemaphoreTester extends Thread {

	private volatile Semaphore semaphore;

	public SemaphoreTester(Semaphore semaphore) {
		this.semaphore = semaphore;
		setDaemon(true);
		start();
	}

	@Override
	public void run() {
		while (true) {
			if (semaphore.available()) {
				yield(); // Makes it fail faster
				semaphore.acquire();
				yield();
				semaphore.release();
				yield();
			}
		}
	}

	public static void main(String[] args) throws Exception {
		Semaphore semaphore = new Semaphore();
		new SemaphoreTester(semaphore);
		new SemaphoreTester(semaphore);
		new InvariantWatcher(semaphore).join(); // 主线程在InvariantWatcher上调用了join(
												// )，这将使程序一直运行，直到发生失败。（InvariantWatcher启动的线程是Daemon）
	}

}

// “照样挂”
class Semaphore implements Invariant {

	private volatile int semaphore = 0;

	public synchronized boolean available() {
		return semaphore == 0;
	}

	public synchronized void acquire() {
		++semaphore;
	}

	public synchronized void release() {
		--semaphore;
	}
	
	public synchronized int getValue() {
		return semaphore;
	}

	public InvariantState invariant() {
		int val = getValue();
		if (val == 0 || val == 1)
			return new InvariantOK();
		else
			return new InvariantFailure(new Integer(val));
	}

}

// 正确的
class Semaphore2 implements Invariant {

	private int semaphore = 0;

	public synchronized int peekValue() {
		return semaphore;
	}

	public synchronized boolean acquire() {
		if (semaphore == 0) {
			++semaphore;
			return true;
		} else
			return false;

	}

	public synchronized void release() {
		-- semaphore;
	}

	public InvariantState invariant() {
		int val = peekValue();
		if (val == 0 || val == 1)
			return new InvariantOK();
		else
			return new InvariantFailure(new Integer(val));
	}

}

class SemaphoreTester2 extends Thread {
	private volatile Semaphore2 semaphore;
	
	public SemaphoreTester2(Semaphore2 semaphore) {
		this.semaphore = semaphore;
		setDaemon(true);
		start();
	}
	
	@Override
	public void run() {
		while(true) {
			if(semaphore.acquire()) {
				semaphore.release();
			}
		}
	}
	
	public static void main(String[] args) throws Exception{
		Semaphore2 sem = new Semaphore2();
		new SemaphoreTester2(sem);
		new SemaphoreTester2(sem);
		new InvariantWatcher(sem, 5000).join();
	}
	
}
